/**
 * BBCode editor actions
 * @param Int id
 */
function DomBBCodeEditor( id ) {
	
	this.id = id;
	
	this.setCursorPosition = function(ctrl, pos){
		if (ctrl.setSelectionRange) {
			ctrl.focus();
			ctrl.setSelectionRange(pos, pos);
		} else if (ctrl.createTextRange) {
			var range = ctrl.createTextRange();
			range.collapse(true);	
			range.moveEnd('character', pos);		
			range.moveStart('character', pos);		
			range.select();	
		}
	}
	
	this.addTag = function(tag1, tag2){
	
		if (tag2 == undefined) {
			tag2 = tag1;
			tag1 = "";
		}
	
		textarea = document.getElementById( this.id  );
		// Code for IE
		if( document.selection ) {
			textarea.focus();
			var sel = document.selection.createRange();
			sel.text = tag1 + sel.text + tag2;
		
		// Code for Mozilla Firefox
		} else { 
			var len = textarea.value.length;
		    var start = textarea.selectionStart;
			var end = textarea.selectionEnd;
			var scrollTop = textarea.scrollTop;
			var scrollLeft = textarea.scrollLeft;
	
	        var sel = textarea.value.substring(start, end);
			var rep = tag1 + sel + tag2;
	        textarea.value =  textarea.value.substring(0,start) + rep + textarea.value.substring(end,len);
			
			textarea.scrollTop = scrollTop;
			textarea.scrollLeft = scrollLeft;
		}
		textarea.focus();
		this.setCursorPosition( textarea, end + tag1.length + tag2.length );
	}
	
	this.addImage = function() {
		textarea = document.getElementById( this.id );
		var url = prompt('Sisestage pildi aadress:','http://');
		var scrollTop = textarea.scrollTop;
		var scrollLeft = textarea.scrollLeft;
	
		if ( document.selection ) {
			textarea.focus();
			var sel = document.selection.createRange();
			sel.text = '[img]' + url + '[/img]';
		} else {
			var len = textarea.value.length;
		    var start = textarea.selectionStart;
			var end = textarea.selectionEnd;
			
	        var sel = textarea.value.substring(start, end);
		    //alert(sel);
			var rep = '[img]' + url + '[/img]';
	        textarea.value =  textarea.value.substring(0,start) + rep + textarea.value.substring(end,len);
			
				
			textarea.scrollTop = scrollTop;
			textarea.scrollLeft = scrollLeft;
		}
	}
	
	this.addUrl = function() {
		textarea = document.getElementById( this.id );
		var url = prompt('Sisestage veebilehe aadress:','http://');
		var scrollTop = textarea.scrollTop;
		var scrollLeft = textarea.scrollLeft;
		
		if( document.selection ) {
			textarea.focus();
			var sel = document.selection.createRange();
					
			if(sel.text==""){
				sel.text = '[url]'  + url + '[/url]';
			} else {
				sel.text = '[url=' + url + ']' + sel.text + '[/url]';
			}			
		} else {
			var len = textarea.value.length;
		    var start = textarea.selectionStart;
			var end = textarea.selectionEnd;
			
	        var sel = textarea.value.substring(start, end);
			
			if(sel==""){
				var rep = '[url]' + url + '[/url]';
			} else {
				var rep = '[url=' + url + ']' + sel + '[/url]';
			}
	        textarea.value =  textarea.value.substring(0,start) + rep + textarea.value.substring(end,len);
					
			textarea.scrollTop = scrollTop;
			textarea.scrollLeft = scrollLeft;
		}
	}
	
}


/**
 * Parses BBCode
 * 
 * Usage:
<code>
var editor = new DomBBCode();
html = editor.parse( text );
</code>
 */
function DomBBCodeParser() {
	
	this.opentags;           // open tag stack
	this.crlf2br = true;     // convert CRLF to <br>?
	this.noparse = false;	// ignore BBCode tags?
	this.urlstart = -1;      // beginning of the URL if zero or greater (ignored if -1)
	
	// aceptable BBcode tags, optionally prefixed with a slash
	this.tagname_re = /^\/?(?:b|i|u|pre|samp|code|colou?r|size|this.noparse|url|s|q|blockquote)$/;
	
	// color names or hex color
	this.color_re = /^(:?black|silver|gray|white|maroon|red|purple|fuchsia|green|lime|olive|yellow|navy|blue|teal|aqua|#(?:[0-9a-f]{3})?[0-9a-f]{3})$/i;
	
	// numbers
	this.number_re = /^[\\.0-9]{1,8}$/i;
	
	// reserved, unreserved, escaped and alpha-numeric [RFC2396]
	this.uri_re = /^[-;\/\?:@&=\+\$,_\.!~\*'\(\)%0-9a-z]{1,512}$/i;
	
	// main regular expression: CRLF, [tag=option], [tag] or [/tag]
	this.postfmt_re = /([\r\n])|(?:\[([a-z]{1,16})(?:=([^\x00-\x1F"'\(\)<>\[\]]{1,256}))?\])|(?:\[\/([a-z]{1,16})\])/ig;
	
	// stack frame object
	this.taginfo_t = function(bbtag, etag) {
	   this.bbtag = bbtag;
	   this.etag = etag;
	}
	
	// check if it's a valid BBCode tag
	this.isValidTag = function(str) {
	   if(!str || !str.length)
	      return false;
	
	   return this.tagname_re.test(str);
	}
	
	//
	// m1 - CR or LF
	// m2 - the tag of the [tag=option] expression
	// m3 - the option of the [tag=option] expression
	// m4 - the end tag of the [/tag] expression
	//
	this.textToHtmlCB = function(mstr, m1, m2, m3, m4, offset, string) {
	   //
	   // CR LF sequences
	   //
	   if(m1 && m1.length) {
	      if(!bbeditor.crlf2br)
	         return mstr;
	
	      switch (m1) {
	         case '\r':
	            return "";
	         case '\n':
	            return "<br>";
	      }
	   }
	
	   //
	   // handle start tags
	   //
	   if( bbeditor.isValidTag(m2) ) {
	      // if in the this.noparse state, just echo the tag
	      if(bbeditor.noparse)
	         return "[" + m2 + "]";
	
	      // ignore any tags if there's an open option-less [url] tag
	      if(bbeditor.opentags.length && bbeditor.opentags[bbeditor.opentags.length-1].bbtag == "url" && bbeditor.urlstart >= 0)
	         return "[" + m2 + "]";
	
	      switch (m2) {
	         case "code":
	            bbeditor.opentags.push(new bbeditor.taginfo_t(m2, "</code></pre>"));
	            bbeditor.crlf2br = false;
	            return "<pre><code>";
	
	         case "pre":
	            bbeditor.opentags.push(new bbeditor.taginfo_t(m2, "</pre>"));
	            bbeditor.crlf2br = false;
	            return "<pre>";
	
	         case "color":
	         case "colour":
	            if(!m3 || !bbeditor.color_re.test(m3))
	               m3 = "inherit";
	            bbeditor.opentags.push(new bbeditor.taginfo_t(m2, "</span>"));
	            return "<span style=\"color: " + m3 + "\">";
	
	         case "size":
	            if(!m3 || !bbeditor.number_re.test(m3))
	               m3 = "1";
	            bbeditor.opentags.push(new bbeditor.taginfo_t(m2, "</span>"));
	            return "<span style=\"font-size: " + Math.min(Math.max(m3, 0.7), 3) + "em\">";
	
	         case "s":
	            bbeditor.opentags.push(new bbeditor.taginfo_t(m2, "</span>"));
	            return "<span style=\"text-decoration: line-through\">";
	
	         case "this.noparse":
	            bbeditor.noparse = true;
	            return "";
	
	         case "url":
	            bbeditor.opentags.push(new bbeditor.taginfo_t(m2, "</a>"));

	            // check if there's a valid option
	            if(m3 && bbeditor.uri_re.test(m3)) {
	               // if there is, output a complete start anchor tag
	               bbeditor.urlstart = -1;
	               return "<a href=\"" + m3 + "\" target=\"_blank\">";
	            }
	
	            // otherwise, remember the URL offset 
	            bbeditor.urlstart = mstr.length + offset;
	
	            // and treat the text following [url] as a URL
	            return "<a target=\"_blank\" href=\"";
	
	         case "q":
	         case "blockquote":
	            bbeditor.opentags.push(new bbeditor.taginfo_t(m2, "</" + m2 + ">"));
	            return m3 && m3.length && bbeditor.uri_re.test(m3) ? "<" + m2 + " cite=\"" + m3 + "\">" : "<" + m2 + ">";
	
	         default:
	            // [samp], [b], [i] and [u] don't need special processing
	            bbeditor.opentags.push(new bbeditor.taginfo_t(m2, "</" + m2 + ">"));
	            return "<" + m2 + ">";
	            
	      }
	   }
	
	   //
	   // process end tags
	   //
	   if( bbeditor.isValidTag(m4) ) {
	      if(bbeditor.noparse) {
	         // if it's the closing this.noparse tag, flip the this.noparse state
	         if(m4 == "this.noparse")  {
	            bbeditor.noparse = false;
	            return "";
	         }
	         
	         // otherwise just output the original text
	         return "[/" + m4 + "]";
	      }
	      
	      // highlight mismatched end tags
	      if(!bbeditor.opentags.length || bbeditor.opentags[bbeditor.opentags.length-1].bbtag != m4)
	         return "<span style=\"color: red\">[/" + m4 + "]</span>";
	
	      if(m4 == "url") {
	         // if there was no option, use the content of the [url] tag
	         if(bbeditor.urlstart > 0)
	            return "\">" + string.substr(bbeditor.urlstart, offset-bbeditor.urlstart) + bbeditor.opentags.pop().etag;
	         
	         // otherwise just close the tag
	         return bbeditor.opentags.pop().etag;
	      }
	      else if(m4 == "code" || m4 == "pre")
	         bbeditor.crlf2br = true;
	
	      // other tags require no special processing, just output the end tag
	      return bbeditor.opentags.pop().etag;
	   }
	
	   return mstr;
	}
	
	//
	// post must be HTML-encoded
	//
	this.parse = function(post) {
		
		bbeditor = this;
		
		var result, endtags, tag;
	
		// convert CRLF to <br> by default
		this.crlf2br = true;
	
		// create a new array for open tags
		if(this.opentags == null || this.opentags.length)
			this.opentags = new Array(0);
	
		// run the text through main regular expression matcher
		result = post.replace(this.postfmt_re, this.textToHtmlCB);
	
		// reset this.noparse, if it was unbalanced
		if(this.noparse)
			this.noparse = false;
		
		// if there are any unbalanced tags, make sure to close them
	   if(this.opentags.length) {
	      endtags = new String();
	   	
			// if there's an open [url] at the top, close it
			if(this.opentags[this.opentags.length-1].bbtag == "url") {
				this.opentags.pop();
				endtags += "\">" + post.substr(this.urlstart, post.length-this.urlstart) + "</a>";
	      }
			
			// close remaining open tags
			while(this.opentags.length)
				endtags += this.opentags.pop().etag;
		}
		
		bbeditor = null;
		
		return endtags ? result + endtags : result;
	}
}
